Allow to construct menu tool buttons.
authorMatthias Clasen <mclasen@redhat.com>
Sun, 19 Jun 2005 03:20:07 +0000 (03:20 +0000)
committerMatthias Clasen <matthiasc@src.gnome.org>
Sun, 19 Jun 2005 03:20:07 +0000 (03:20 +0000)
2005-06-18  Matthias Clasen  <mclasen@redhat.com>

* gtk/gtkuimanager.c: Allow to construct menu tool buttons.

* demos/gtk-demo/appwindow.c: Demonstrate menu tool buttons
constructed with GtkUIManager.

ChangeLog
ChangeLog.pre-2-10
ChangeLog.pre-2-8
demos/gtk-demo/appwindow.c
docs/reference/ChangeLog
docs/reference/gtk/tmpl/gtkuimanager.sgml
gtk/gtkuimanager.c

index 98ecaf8076c91d9c08972b96a053f1b18a29382c..825d2dec2a890bb6466052b96ddaa104280d1ab9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,10 @@
 2005-06-18  Matthias Clasen  <mclasen@redhat.com>
 
+       * gtk/gtkuimanager.c: Allow to construct menu tool buttons.
+
+       * demos/gtk-demo/appwindow.c: Demonstrate menu tool buttons
+       constructed with GtkUIManager.
+
        * gtk/gtk.symbols: 
        * gtk/gtkimage.h: 
        * gtk/gtkimage.c (gtk_image_clear): Make this function
index 98ecaf8076c91d9c08972b96a053f1b18a29382c..825d2dec2a890bb6466052b96ddaa104280d1ab9 100644 (file)
@@ -1,5 +1,10 @@
 2005-06-18  Matthias Clasen  <mclasen@redhat.com>
 
+       * gtk/gtkuimanager.c: Allow to construct menu tool buttons.
+
+       * demos/gtk-demo/appwindow.c: Demonstrate menu tool buttons
+       constructed with GtkUIManager.
+
        * gtk/gtk.symbols: 
        * gtk/gtkimage.h: 
        * gtk/gtkimage.c (gtk_image_clear): Make this function
index 98ecaf8076c91d9c08972b96a053f1b18a29382c..825d2dec2a890bb6466052b96ddaa104280d1ab9 100644 (file)
@@ -1,5 +1,10 @@
 2005-06-18  Matthias Clasen  <mclasen@redhat.com>
 
+       * gtk/gtkuimanager.c: Allow to construct menu tool buttons.
+
+       * demos/gtk-demo/appwindow.c: Demonstrate menu tool buttons
+       constructed with GtkUIManager.
+
        * gtk/gtk.symbols: 
        * gtk/gtkimage.h: 
        * gtk/gtkimage.c (gtk_image_clear): Make this function
index 5cf00815d37399491097f12a9f7913c47e42c5e4..7f2d7986a9b8f1bcda9823951703f0005cc57df8 100644 (file)
@@ -1,6 +1,6 @@
 /* Application main window
  *
- * Demonstrates a typical application window, with menubar, toolbar, statusbar.
+ * Demonstrates a typical application window with menubar, toolbar, statusbar.
  */
 
 #include <gtk/gtk.h>
@@ -144,9 +144,32 @@ about_cb (GtkAction *action,
   g_object_unref (transparent);
 }
 
+typedef struct 
+{
+  GtkAction action;
+} ToolMenuAction;
+
+typedef struct 
+{
+  GtkActionClass parent_class;
+} ToolMenuActionClass;
+
+G_DEFINE_TYPE(ToolMenuAction, tool_menu_action, GTK_TYPE_ACTION);
+
+static void
+tool_menu_action_class_init (ToolMenuActionClass *class)
+{
+  GTK_ACTION_CLASS (class)->toolbar_item_type = GTK_TYPE_MENU_TOOL_BUTTON;
+}
+
+static void
+tool_menu_action_init (ToolMenuAction *action)
+{
+}
 
 static GtkActionEntry entries[] = {
   { "FileMenu", NULL, "_File" },               /* name, stock id, label */
+  { "OpenMenu", NULL, "_Open" },               /* name, stock id, label */
   { "PreferencesMenu", NULL, "_Preferences" }, /* name, stock id, label */
   { "ColorMenu", NULL, "_Color"  },            /* name, stock id, label */
   { "ShapeMenu", NULL, "_Shape" },             /* name, stock id, label */
@@ -155,9 +178,9 @@ static GtkActionEntry entries[] = {
     "_New", "<control>N",                      /* label, accelerator */
     "Create a new file",                       /* tooltip */ 
     G_CALLBACK (activate_action) },      
-  { "Open", GTK_STOCK_OPEN,                    /* name, stock id */
-    "_Open","<control>O",                      /* label, accelerator */     
-    "Open a file",                             /* tooltip */
+  { "File1", NULL,                             /* name, stock id */
+    "File1", NULL,                             /* label, accelerator */     
+    "Open first file",                         /* tooltip */
     G_CALLBACK (activate_action) }, 
   { "Save", GTK_STOCK_SAVE,                    /* name, stock id */
     "_Save","<control>S",                      /* label, accelerator */     
@@ -258,8 +281,12 @@ static const gchar *ui_info =
 "      <menuitem action='About'/>"
 "    </menu>"
 "  </menubar>"
-"  <toolbar  name='ToolBar'>"
-"    <toolitem action='Open'/>"
+"  <toolbar name='ToolBar'>"
+"    <toolitem action='Open'>"
+"      <menu action='OpenMenu'>"
+"        <menuitem action='File1'/>"
+"      </menu>"  
+"    </toolitem>"
 "    <toolitem action='Quit'/>"
 "    <separator action='Sep1'/>"
 "    <toolitem action='Logo'/>"
@@ -394,6 +421,7 @@ do_appwindow (GtkWidget *do_widget)
       GtkWidget *bar;
       GtkTextBuffer *buffer;
       GtkActionGroup *action_group;
+      GtkAction *open_action;
       GtkUIManager *merge;
       GError *error = NULL;
 
@@ -421,6 +449,13 @@ do_appwindow (GtkWidget *do_widget)
        */
       
       action_group = gtk_action_group_new ("AppWindowActions");
+      open_action = g_object_new (tool_menu_action_get_type (), 
+                                 "name", "Open",
+                                 "label", "_Open",
+                                 "tooltip", "Open a file",
+                                 "stock-id", GTK_STOCK_OPEN,
+                                 NULL);
+      gtk_action_group_add_action (action_group, open_action);
       gtk_action_group_add_actions (action_group, 
                                    entries, n_entries, 
                                    window);
index 42d5fdcd5a29a666f57916cae161e3ce5c033ee2..ad452d8d38da55575605d7f871cbdf2e8876bdb9 100644 (file)
@@ -1,5 +1,8 @@
 2005-06-18  Matthias Clasen  <mclasen@redhat.com>
 
+       * gtk/tmpl/gtkuimanager.sgml: Document that 
+       toolitem elements may have menu subelements.
+
        * gtk/gtk-sections.txt: Updates
 
 2005-06-17  Matthias Clasen  <mclasen@redhat.com>
index ac3b5aa995f4242f7ea974a4fa49e8c1fd65746b..956617f290e7c7533e542499496675c4a17df04d 100644 (file)
@@ -22,7 +22,7 @@ roughly described by the following DTD.
 &lt;!ELEMENT toolbar     (toolitem|separator|placeholder)* &gt;
 &lt;!ELEMENT placeholder (menuitem|toolitem|separator|placeholder|menu)* &gt;
 &lt;!ELEMENT menuitem     EMPTY &gt;
-&lt;!ELEMENT toolitem     EMPTY &gt;
+&lt;!ELEMENT toolitem     (menu?) &gt;
 &lt;!ELEMENT separator    EMPTY &gt;
 &lt;!ELEMENT accelerator  EMPTY &gt;
 &lt;!ATTLIST menubar      name                  &num;IMPLIED 
@@ -115,7 +115,8 @@ action</para></listitem>
 </varlistentry>
 <varlistentry><term>toolitem</term>
 <listitem><para>a #GtkToolItem subclass, the exact type depends on the
-action</para></listitem> 
+action. Note that toolitem elements may contain a menu element, but only
+if their associated action specifies a #GtkMenuToolButton as proxy.</para></listitem> 
 </varlistentry>
 <varlistentry><term>separator</term>
 <listitem><para>a #GtkSeparatorMenuItem or
index d5e759c59d65db9697b5b6972e5d035849003989..ee690925bc922b99dc6c4e20d80dbc9cd8982431 100644 (file)
@@ -36,6 +36,7 @@
 #include "gtkmenu.h"
 #include "gtkmenubar.h"
 #include "gtkmenushell.h"
+#include "gtkmenutoolbutton.h"
 #include "gtkseparatormenuitem.h"
 #include "gtkseparatortoolitem.h"
 #include "gtktearoffmenuitem.h"
@@ -859,11 +860,6 @@ get_child_node (GtkUIManager *self,
 {
   GNode *child = NULL;
 
-  g_return_val_if_fail (parent == NULL ||
-                       (NODE_INFO (parent)->type != NODE_TYPE_MENUITEM &&
-                        NODE_INFO (parent)->type != NODE_TYPE_TOOLITEM), 
-                       NULL);
-
   if (parent)
     {
       if (childname)
@@ -1213,6 +1209,21 @@ start_element_handler (GMarkupParseContext *context,
 
          node_prepend_ui_reference (ctx->current, ctx->merge_id, action_quark);
          
+         raise_error = FALSE;
+       }
+      else if (ctx->state == STATE_TOOLITEM && !strcmp (element_name, "menu"))
+       {
+         ctx->state = STATE_MENU;
+         
+         ctx->current = get_child_node (self, g_node_last_child (ctx->current),
+                                        node_name, strlen (node_name),
+                                        NODE_TYPE_MENU,
+                                        TRUE, top);
+         if (NODE_INFO (ctx->current)->action_name == 0)
+           NODE_INFO (ctx->current)->action_name = action_quark;
+
+         node_prepend_ui_reference (ctx->current, ctx->merge_id, action_quark);
+         
          raise_error = FALSE;
        }
       else if (ctx->state == STATE_MENU && !strcmp (element_name, "menuitem"))
@@ -1373,6 +1384,11 @@ end_element_handler (GMarkupParseContext *context,
       ctx->current = ctx->current->parent;
       if (NODE_INFO (ctx->current)->type == NODE_TYPE_ROOT) 
        ctx->state = STATE_ROOT;
+      else if (NODE_INFO (ctx->current)->type == NODE_TYPE_TOOLITEM)
+       {
+         ctx->current = ctx->current->parent;
+         ctx->state = STATE_TOOLITEM;
+       }
       /* else, stay in same state */
       break;
     case STATE_MENUITEM:
@@ -2141,7 +2157,10 @@ update_node (GtkUIManager *self,
          GtkWidget *menu;
          GList *siblings;
          
-         menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (info->proxy));
+         if (GTK_IS_MENU (info->proxy))
+           menu = info->proxy;
+         else
+           menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (info->proxy));
          siblings = gtk_container_get_children (GTK_CONTAINER (menu));
          if (siblings != NULL && GTK_IS_TEAROFF_MENU_ITEM (siblings->data))
            {
@@ -2187,12 +2206,16 @@ update_node (GtkUIManager *self,
        if (info->proxy &&  
            G_OBJECT_TYPE (info->proxy) != GTK_ACTION_GET_CLASS (action)->menu_item_type)
          {
-           prev_submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (info->proxy));
-           if (prev_submenu)
+           if (GTK_IS_MENU_ITEM (info->proxy))
              {
-               g_object_ref (prev_submenu);
-               gtk_menu_item_set_submenu (GTK_MENU_ITEM (info->proxy), NULL);
+               prev_submenu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (info->proxy));
+               if (prev_submenu)
+                 {
+                   g_object_ref (prev_submenu);
+                   gtk_menu_item_set_submenu (GTK_MENU_ITEM (info->proxy), NULL);
+               }
              }
+
            gtk_action_disconnect_proxy (info->action, info->proxy);
            gtk_container_remove (GTK_CONTAINER (info->proxy->parent),
                                  info->proxy);
@@ -2205,16 +2228,13 @@ update_node (GtkUIManager *self,
            GtkWidget *menushell;
            gint pos;
            
-           if (find_menu_position (node, &menushell, &pos))
+           if (NODE_INFO (node->parent)->type == NODE_TYPE_TOOLITEM ||
+               find_menu_position (node, &menushell, &pos))
              {
                GtkWidget *tearoff;
                GtkWidget *filler;
                
-               info->proxy = gtk_action_create_menu_item (action);
-               g_object_ref (info->proxy);
-               gtk_object_sink (GTK_OBJECT (info->proxy));
                menu = gtk_menu_new ();
-               gtk_widget_set_name (info->proxy, info->name);
                gtk_widget_set_name (menu, info->name);
                tearoff = gtk_tearoff_menu_item_new ();
                gtk_widget_set_no_show_all (tearoff, TRUE);
@@ -2226,10 +2246,27 @@ update_node (GtkUIManager *self,
                gtk_widget_set_sensitive (filler, FALSE);
                gtk_widget_set_no_show_all (filler, TRUE);
                gtk_menu_shell_append (GTK_MENU_SHELL (menu), filler);
-               gtk_menu_item_set_submenu (GTK_MENU_ITEM (info->proxy), menu);
-               gtk_menu_shell_insert (GTK_MENU_SHELL (menushell), info->proxy, pos);
-               g_signal_connect (info->proxy, "notify::visible",
-                                 G_CALLBACK (update_smart_separators), NULL);
+
+               if (NODE_INFO (node->parent)->type == NODE_TYPE_TOOLITEM)
+                 {
+                   info->proxy = menu;
+                   g_object_ref (info->proxy);
+                   gtk_object_sink (GTK_OBJECT (info->proxy));
+                   gtk_menu_tool_button_set_menu (GTK_MENU_TOOL_BUTTON (NODE_INFO (node->parent)->proxy),
+                                                  menu);
+                 }
+               else
+                 {
+                   info->proxy = gtk_action_create_menu_item (action);
+                   g_object_ref (info->proxy);
+                   gtk_object_sink (GTK_OBJECT (info->proxy));
+                   g_signal_connect (info->proxy, "notify::visible",
+                                     G_CALLBACK (update_smart_separators), NULL);
+                   gtk_widget_set_name (info->proxy, info->name);
+                   
+                   gtk_menu_item_set_submenu (GTK_MENU_ITEM (info->proxy), menu);
+                   gtk_menu_shell_insert (GTK_MENU_SHELL (menushell), info->proxy, pos);
+                 }
              }
          }
        else
@@ -2241,7 +2278,11 @@ update_node (GtkUIManager *self,
                                       prev_submenu);
            g_object_unref (prev_submenu);
          }
-       menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (info->proxy));
+       
+       if (GTK_IS_MENU (info->proxy))
+         menu = info->proxy;
+       else
+         menu = gtk_menu_item_get_submenu (GTK_MENU_ITEM (info->proxy));
        siblings = gtk_container_get_children (GTK_CONTAINER (menu));
        if (siblings != NULL && GTK_IS_TEAROFF_MENU_ITEM (siblings->data))
          {
@@ -2422,7 +2463,7 @@ update_node (GtkUIManager *self,
       break;
     case NODE_TYPE_TOOLITEM:
       /* remove the proxy if it is of the wrong type ... */
-      if (info->proxy &&  
+      if (info->proxy && 
          G_OBJECT_TYPE (info->proxy) != GTK_ACTION_GET_CLASS (action)->toolbar_item_type)
        {
          g_signal_handlers_disconnect_by_func (info->proxy,
@@ -2454,7 +2495,7 @@ update_node (GtkUIManager *self,
               * tooltips on toolitems can't be set before the toolitem 
               * is added to the toolbar.
               */
-              g_object_notify (G_OBJECT (action), "tooltip");
+             g_object_notify (G_OBJECT (action), "tooltip");
            }
        }
       else
@@ -2560,9 +2601,11 @@ update_node (GtkUIManager *self,
   
   if (info->proxy) 
     {
-      if (info->type == NODE_TYPE_MENU) 
+      if (info->type == NODE_TYPE_MENU && GTK_IS_MENU_ITEM (info->proxy)
        update_smart_separators (gtk_menu_item_get_submenu (GTK_MENU_ITEM (info->proxy)));
-      else if (info->type == NODE_TYPE_TOOLBAR || info->type == NODE_TYPE_POPUP) 
+      else if (info->type == NODE_TYPE_MENU || 
+              info->type == NODE_TYPE_TOOLBAR || 
+              info->type == NODE_TYPE_POPUP) 
        update_smart_separators (info->proxy);
     }